package com.broada.apm.filter;

import java.io.IOException;
import java.util.Base64;
import java.util.Optional;
import java.util.stream.Stream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.cache.RoleAuthorizationManager;
import com.broada.apm.indicator.api.ApmClientFactory;
import com.broada.apm.indicator.api.UserService;
import com.broada.apm.model.User;
import com.broada.apm.util.MD5Util;
import com.broada.apm.util.TokenManager;
import com.broada.apm.utils.ExceptionUtils;
import com.google.common.base.Strings;
@WebFilter("/rest/*")
public class AuthorizationFilter implements Filter {
	
	Logger logger = LoggerFactory.getLogger(AuthorizationFilter.class);
    /*
     * 免登录url
     */
    private String[] freeUris = { "login", "logout", "licreq", "licimport", "system/systime" };

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String url = req.getPathInfo();
        if(isFreeUri(url) || checkHeaderAuth(req, res) || checkTokenAuth(req, res) ) {
    		// 以此检查 是否是 免登录地址，header中的auth 信息，url中的token信息
    	}else if("true".equals(System.getProperty("freelogin", "false"))) {
    		// 系统免登录
    	} else {
    		// 验证失败，禁止后续执行
			res.sendError(401, "登录超时,请重新登录.");
            res.getOutputStream().close();
            return;
    	}
        chain.doFilter(request, response);
    }

	private boolean checkTokenAuth(HttpServletRequest req, HttpServletResponse res) {
		try {
			String token = findTokenFromUrlOrCookie(req);
			String url = req.getPathInfo();
			String method = req.getMethod();
			User user = TokenManager.getUser(token);
			if (user != null  && RoleAuthorizationManager.getInstance().isAllow(user.getRole(), url, method)) { // 已经有用户登录
				return true;
			}
		} catch (Exception e) {
			ExceptionUtils.error(logger, "验证token信息失败", e);
			return false;
		}
		return false;
	}

	private String findTokenFromUrlOrCookie(HttpServletRequest req) {
        String token = req.getParameter("token");
        if (Strings.isNullOrEmpty(token)) {
        	if(req.getCookies() == null)
        		return "";
            Optional<Cookie> tokenCookie = Stream.of(req.getCookies()).filter(c -> {
                return c.getName().equals("token");
            }).findFirst();
            token = tokenCookie.isPresent() ? tokenCookie.get().getValue() : "";
        }
        return token;
    }

    private boolean isFreeUri(String url) {
        return Stream.of(freeUris).filter(u -> url.endsWith(u)).findAny().isPresent();
    }
    
    // http基本认证
    private boolean checkHeaderAuth(HttpServletRequest request, HttpServletResponse response) {
    	  try{
			String auth = request.getHeader("Authorization");
			if ((auth != null) && (auth.length() > 6)) {
				String authInfo = new String(Base64.getDecoder().decode(auth.substring("Basic ".length())));
				if (authInfo != null) {
					String userAndPasswd[] = authInfo.split(":");
					if (userAndPasswd.length != 2)
						return false;
					UserService userService = ApmClientFactory.getApmClient().getUserService();
					User user = userService.getUserByAccount(userAndPasswd[0]);
					if (user != null && user.getStatus() == 0
							&& MD5Util.string2MD5(userAndPasswd[1]).equals(user.getPassword())) {
						return true;
					}
				}
				return false;
			} else {
				return false;
			}
		} catch (Exception e) {
			ExceptionUtils.error(logger, "验证头消息中用户信息失败", e);
			return false;
		}
    }  

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

}
